//此模块主要完成开路侦测与短路侦测//

`timescale 1ns/1ps
`default_nettype none

`define GetPwmBits(lsb, num) I_cfg_pwm_setting[lsb+num-1:lsb]

module open_detect_mbi5353
    #(
    parameter   DW      = 96
    )
    (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    // control
    input  wire         I_enable,
    input  wire         I_detect_start,
    output wire         O_detect_done,
    // config
    input  wire [4:0]   I_cfg_scan_max,      // 最大扫描id
    input  wire [511:0] I_cfg_pwm_setting,   // pwm芯片设置
    // scan output
    output wire         O_scan_prep,
    output wire         O_scan_commit,
    output wire [4:0]   O_scan_num,
    // data shift
    output wire         O_shift_req,
    input  wire         I_shift_busy,
    output wire [9:0]   O_shift_bit_num,
    output wire [4:0]   O_shift_load_num,
    output wire [DW-1:0] O_shift_data,
    input  wire         I_shift_data_ack,
    // gclk
    output wire         O_gclk_out
);
//------------------------Parameter----------------------
localparam [4:0]
    IDLE        = 0,
    RESET0      = 1,
    RESET1      = 2,
    PRE0        = 3,
    PRE1        = 4,
    CONFIG0     = 5,
    CONFIG1     = 6,
    SCAN0       = 7,
    SCAN1       = 8,
    DETECT_ON0  = 9,
    DETECT_ON1  = 10,
    DELAY       = 11,
    DETECT_OFF0 = 12,
    DETECT_OFF1 = 13,
    LOOP0       = 14,
    LOOP1       = 15,
    PRE2        = 16,
    PRE3        = 17,
    RECONFIG0   = 18,
    RECONFIG1   = 19,
    OVER        = 20;

//------------------------Local signal-------------------
//fsm
reg  [4:0]  state;
reg  [4:0]  next;
reg  [14:0] delay_cnt;
reg  [2:0]  config_cnt;

//detect
reg         detect_done;
// scan
reg         scan_prep;
reg         scan_commit;
reg  [4:0]  scan_num;
reg         scan_commit_flag_1;
reg         scan_prep_flag;

// data shift
reg         shift_req;
reg         shift_busy_last;
wire        shift_done;
reg  [9:0]  shift_bit_num;
reg  [3:0]  shift_load_num;
reg  [DW-1:0] shift_data;
reg  [47:0] port_reg;
//gclk
reg         gclk_out;

//reg
wire [5:0]  cfg_chip_num;      // 串移链中芯片数量
wire [15:0] cfg_port0_reg1;    // port0寄存器1的值 R1
wire [15:0] cfg_port0_reg2;    // port0寄存器2的值 R2
wire [15:0] cfg_port0_reg3;    // port0寄存器3的值 R3
wire [15:0] cfg_port1_reg1;    // port1寄存器1的值 G1
wire [15:0] cfg_port1_reg2;    // port1寄存器2的值 G2
wire [15:0] cfg_port1_reg3;    // port1寄存器3的值 G3
wire [15:0] cfg_port2_reg1;    // port2寄存器1的值 B1
wire [15:0] cfg_port2_reg2;    // port2寄存器2的值 B2
wire [15:0] cfg_port2_reg3;    // port2寄存器3的值 B3
wire [15:0] cfg_port3_reg1;    // 通用 寄存器1的值
wire [15:0] cfg_port3_reg2;    // 通用 寄存器2的值
wire [15:0] cfg_port3_reg3;    // 通用 寄存器3的值
//------------------------Instantiation------------------

//------------------------Body---------------------------
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
assign cfg_chip_num      = `GetPwmBits(56, 6);
assign cfg_port0_reg1    = `GetPwmBits(64, 16);
assign cfg_port0_reg2    = `GetPwmBits(80, 16);
assign cfg_port0_reg3    = `GetPwmBits(96, 16);
assign cfg_port1_reg1    = `GetPwmBits(112, 16);
assign cfg_port1_reg2    = `GetPwmBits(128, 16);
assign cfg_port1_reg3    = `GetPwmBits(144, 16);
assign cfg_port2_reg1    = `GetPwmBits(160, 16);
assign cfg_port2_reg2    = `GetPwmBits(176, 16);
assign cfg_port2_reg3    = `GetPwmBits(192, 16);
assign cfg_port3_reg1    = `GetPwmBits(216, 16);  
assign cfg_port3_reg2    = `GetPwmBits(232, 16);
assign cfg_port3_reg3    = `GetPwmBits(248, 16);

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        state <= IDLE;
    else if(!I_enable)
        state <= IDLE;
    else
        state <= next;
end

always @(*)
begin
    case(state)
        IDLE: begin
            if(I_detect_start)
                next = RESET0;
            else
                next = IDLE;
        end
        RESET0: begin
            next = RESET1;
        end
        RESET1: begin
            if(!shift_done)
                next = RESET1;
            else
                next = PRE0;
        end
        PRE0: begin
            next = PRE1;
        end
        PRE1: begin
            if(!shift_done)
                next = PRE1;
            else
                next = CONFIG0;
        end
        CONFIG0: begin
            next = CONFIG1;
        end
        CONFIG1: begin
            if(!shift_done)
                next = CONFIG1;
            else if(config_cnt == 4)
                next = SCAN0;
            else
                next = PRE0;
        end
        SCAN0: begin
            next = SCAN1;
        end
        SCAN1: begin
            if(delay_cnt != 1'b1)
                next = SCAN1;
            else if(scan_commit_flag_1)//(scan_num == 1'b0)
                next = DETECT_ON0;
            else 
                next = SCAN0;
        end
        DETECT_ON0: begin
            next = DETECT_ON1;
        end
        DETECT_ON1: begin
            if(!shift_done)
                next = DETECT_ON1;
            else
                next = DELAY; 
        end
        DELAY: begin
            if(delay_cnt == 1'b1)
                next = DETECT_OFF0; 
            else
                next = DELAY;
        end
        DETECT_OFF0: begin
             next = DETECT_OFF1;
            end
        DETECT_OFF1: begin
            if(!shift_done)
                next = DETECT_OFF1;
            else
                next = LOOP0;
            end
        LOOP0: begin
            next = LOOP1;
        end
        LOOP1: begin
            if(delay_cnt != 1'b1)
                next = LOOP1;
            else if(scan_prep_flag)//(scan_prep && scan_num == 1'b0)
                next = PRE2;
            else
                next = DETECT_ON0;
            end
        PRE2: begin
            next = PRE3;
        end
        PRE3: begin
            if(!shift_done)
                next = PRE3;
            else
                next = RECONFIG0;
        end
        RECONFIG0: begin
            next = RECONFIG1;
        end
        RECONFIG1: begin
            if(!shift_done)
                next = RECONFIG1;
            else if(config_cnt == 4)
				    next =OVER;
				else
                next =PRE2;
			  end
        OVER: begin
            next = IDLE;
            end
        default: next = IDLE;
    endcase
end

//gclk
assign O_gclk_out = 1'b0;

//config_cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        config_cnt <= 1'b0;
    else if(state == IDLE)
        config_cnt <= 1'b0;
    else if(state == CONFIG0 || state == RECONFIG0)
        config_cnt <= config_cnt + 1'b1;
    else if(state == DETECT_ON0)
        config_cnt <= 1'b0;		  
end

//delay_cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        delay_cnt <= 1'b0;
    else if(state==SCAN0)
        delay_cnt <= 12'd2200;   //延时17.6us
    else if(state == LOOP0)
        delay_cnt <= 13'd8000;   //侦测换行，延时64us
    else if(state == DETECT_ON1 && shift_done)
        delay_cnt <= 15'd26000;  //错误侦测时间，延时>200us
    else if(delay_cnt != 1'b0)
        delay_cnt <= delay_cnt - 1'b1;
end

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
assign O_scan_prep   = scan_prep;
assign O_scan_commit = scan_commit;
assign O_scan_num    = scan_num;

// scan_prep
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        scan_prep <= 1'b0;
    else if(state == SCAN0)
        scan_prep <= 1'b1;
    else if(state==LOOP0)
        scan_prep <= 1'b1;
    else
        scan_prep <= 1'b0;
end

// scan_commit
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        scan_commit <= 1'b0;
    else if(state == SCAN1 && delay_cnt == 8'd200)
        scan_commit <= 1'b1;
    else if(state == LOOP1 && delay_cnt == 8'd200)
        scan_commit <= 1'b1;
    else
        scan_commit <= 1'b0;
end

// scan_num
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        scan_num <= 1'b0;
    else if(state == IDLE)
        scan_num <= 1'b1;
    else if(scan_prep) begin
        if(scan_num == I_cfg_scan_max)
            scan_num <= 1'b0;
        else
            scan_num <= scan_num + 1'b1;
    end
end

//scan_commit_flag
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        scan_commit_flag_1 <= 1'b0;
    else if(state == SCAN1 && scan_num == 1'b1 && scan_commit == 1'b1)
        scan_commit_flag_1 <= 1'b1;
    else if(state == DETECT_ON0)
        scan_commit_flag_1 <= 1'b0;
end

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        scan_prep_flag <= 1'b0;
    else if(state == LOOP1 && scan_num == 1'b0 && scan_prep == 1'b1)
        scan_prep_flag <= 1'b1;
    else if(state == PRE2)
        scan_prep_flag <= 1'b0;
end
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
assign O_shift_req      = shift_req;
assign O_shift_bit_num  = shift_bit_num;
assign O_shift_load_num = shift_load_num;
assign O_shift_data     = shift_data;

assign shift_done = shift_busy_last && !I_shift_busy;

// shift_req
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_req <= 1'b0; 
    else if(state == RESET0 || state == PRE0 ||state == CONFIG0 || state == DETECT_ON0 || state == DETECT_OFF0 || state == RECONFIG0 || state == PRE2)
        shift_req <= 1'b1; 
    else
        shift_req <= 1'b0; 
end

// shift_busy_last
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        shift_busy_last <= 1'b0;
    else
        shift_busy_last <= I_shift_busy;
end

//shift_bit_num  
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_bit_num <= 1'b0;
    else if(state == RESET0)
        shift_bit_num <= 10'd16;
    else if(state == PRE0 || state == PRE2)
        shift_bit_num <= 10'd16;
    else if(state == CONFIG0 || state == RECONFIG0)
        shift_bit_num <=3* {cfg_chip_num,4'd0};      //移动数据量为48*芯片个数
    else if(state == DETECT_ON0)
        shift_bit_num <= 10'd16;
    else if(state == DETECT_OFF0)
        shift_bit_num <= 10'd16;
    else if(state == RECONFIG0)
        shift_bit_num <= 10'd16;
end

//shift_load_num
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_load_num <= 1'b0; 
    else if(state == RESET0)
        shift_load_num <= 4'd10;
    else if(state == PRE0 || state == PRE2)
        shift_load_num <= 4'd14;
    else if(state == CONFIG0) begin
        shift_load_num <= 4'd4;    
    end
    else if(state == RECONFIG0)   //再次配置
        shift_load_num <= 4'd4;
    else if(state == DETECT_ON0 && cfg_port3_reg2[5])  //开路侦测
		  shift_load_num <= 4'd9;
    else if(state == DETECT_ON0 && cfg_port3_reg2[15] && !cfg_port3_reg2[5]) //短路侦测
        shift_load_num <= 4'd13;    
    else if(state == DETECT_OFF0)
        shift_load_num <= 4'd1;
end

//shift_data
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_data <= 0;
    else if(state == CONFIG1 || state == RECONFIG0)
        shift_data <= {DW{port_reg[47]}};
end


//port_reg  寄存器配置
always @(posedge I_sclk or negedge I_rst_n) begin
   if (~I_rst_n)
        port_reg <= 1'b0;
	else if(state == CONFIG0) begin
		 case(config_cnt) 
			 3'd0: port_reg <= {2'b00,cfg_port3_reg1[13:0],1'b0,cfg_port3_reg2[14:6],1'b1,cfg_port3_reg2[4:0],cfg_port3_reg3};                              //通用寄存器配置
			 3'd1: port_reg <= {2'b01,cfg_port0_reg1[13:0],cfg_port0_reg2[15:12],4'b0000,cfg_port0_reg2[7:6],1'b0,cfg_port0_reg2[4:0],cfg_port0_reg3}; // R  寄存器配置
			 3'd2: port_reg <= {2'b10,cfg_port1_reg1[13:0],cfg_port1_reg2[15:12],4'b0000,cfg_port1_reg2[7:6],1'b0,cfg_port1_reg2[4:0],cfg_port1_reg3}; // G  寄存器配置
			 3'd3: port_reg <= {2'b11,cfg_port2_reg1[13:0],cfg_port2_reg2[15:12],4'b0000,cfg_port2_reg2[7:6],1'b0,cfg_port2_reg2[4:0],cfg_port2_reg3}; // B  寄存器配置
			default:port_reg <= 0;
		  endcase 
	 end
	 else if(state == RECONFIG0) begin
		case(config_cnt)
			 3'd0: port_reg <= {2'b00,cfg_port3_reg1[13:0],1'b0,cfg_port3_reg2[15:6],1'b0,cfg_port3_reg2[4:0],cfg_port3_reg3};                              //通用寄存器配置
			 3'd1: port_reg <= {2'b01,cfg_port0_reg1[13:0],cfg_port0_reg2[15:6],1'b1,cfg_port0_reg2[4:0],cfg_port0_reg3}; // R  寄存器配置
			 3'd2: port_reg <= {2'b10,cfg_port1_reg1[13:0],cfg_port1_reg2[15:6],1'b1,cfg_port1_reg2[4:0],cfg_port1_reg3}; // G  寄存器配置
			 3'd3: port_reg <= {2'b11,cfg_port2_reg1[13:0],cfg_port2_reg2[15:6],1'b1,cfg_port2_reg2[4:0],cfg_port2_reg3}; // B  寄存器配置
			default:port_reg <= 0;
		  endcase
		end
    else if(I_shift_data_ack)
         port_reg <= {port_reg[46:0], port_reg[47]};
end

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//O_detect_done
assign O_detect_done = detect_done;

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        detect_done <= 1'b0;
    else if(state == OVER)
        detect_done <= 1'b1;
    else
        detect_done <= 1'b0;
end


endmodule


